//===----------------------------------------------------------------------===//
//
// This source file is part of the Soto for AWS open source project
//
// Copyright (c) 2017-2024 the Soto project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Soto project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

// THIS FILE IS AUTOMATICALLY GENERATED by https://github.com/soto-project/soto-codegenerator.
// DO NOT EDIT.

#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
@_spi(SotoInternal) import SotoCore

extension BCMRecommendedActions {
    // MARK: Enums

    public enum ActionType: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case addAlternateBillingContact = "ADD_ALTERNATE_BILLING_CONTACT"
        case createAnomalyMonitor = "CREATE_ANOMALY_MONITOR"
        case createBudget = "CREATE_BUDGET"
        case enableCostOptimizationHub = "ENABLE_COST_OPTIMIZATION_HUB"
        case migrateToGranularPermissions = "MIGRATE_TO_GRANULAR_PERMISSIONS"
        case paymentsDue = "PAYMENTS_DUE"
        case paymentsPastDue = "PAYMENTS_PAST_DUE"
        case reviewAnomalies = "REVIEW_ANOMALIES"
        case reviewBudgetAlerts = "REVIEW_BUDGET_ALERTS"
        case reviewBudgetsExceeded = "REVIEW_BUDGETS_EXCEEDED"
        case reviewExpiringRi = "REVIEW_EXPIRING_RI"
        case reviewExpiringSp = "REVIEW_EXPIRING_SP"
        case reviewFreetierUsageAlerts = "REVIEW_FREETIER_USAGE_ALERTS"
        case reviewSavingsOpportunityRecommendations = "REVIEW_SAVINGS_OPPORTUNITY_RECOMMENDATIONS"
        case updateExpiredPaymentMethod = "UPDATE_EXPIRED_PAYMENT_METHOD"
        case updateInvalidPaymentMethod = "UPDATE_INVALID_PAYMENT_METHOD"
        case updateTaxExemptionCertificate = "UPDATE_TAX_EXEMPTION_CERTIFICATE"
        case updateTaxRegistrationNumber = "UPDATE_TAX_REGISTRATION_NUMBER"
        public var description: String { return self.rawValue }
    }

    public enum Feature: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case account = "ACCOUNT"
        case budgets = "BUDGETS"
        case costAnomalyDetection = "COST_ANOMALY_DETECTION"
        case costOptimizationHub = "COST_OPTIMIZATION_HUB"
        case freeTier = "FREE_TIER"
        case iam = "IAM"
        case payments = "PAYMENTS"
        case reservations = "RESERVATIONS"
        case savingsPlans = "SAVINGS_PLANS"
        case taxSettings = "TAX_SETTINGS"
        public var description: String { return self.rawValue }
    }

    public enum FilterName: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case feature = "FEATURE"
        case severity = "SEVERITY"
        case type = "TYPE"
        public var description: String { return self.rawValue }
    }

    public enum MatchOption: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case equals = "EQUALS"
        case notEquals = "NOT_EQUALS"
        public var description: String { return self.rawValue }
    }

    public enum Severity: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case critical = "CRITICAL"
        case info = "INFO"
        case warning = "WARNING"
        public var description: String { return self.rawValue }
    }

    public enum ValidationExceptionReason: String, CustomStringConvertible, Codable, Sendable, CodingKeyRepresentable {
        case cannotParse = "cannotParse"
        case fieldValidationFailed = "fieldValidationFailed"
        case other = "other"
        case unknownOperation = "unknownOperation"
        public var description: String { return self.rawValue }
    }

    // MARK: Shapes

    public struct ActionFilter: AWSEncodableShape {
        /// The category to filter on. Valid values are FEATURE for feature type, SEVERITY for severity level, and TYPE for recommendation type.
        public let key: FilterName
        /// Specifies how to apply the filter. Use EQUALS to include matching results or NOT_EQUALS to exclude matching results.
        public let matchOption: MatchOption
        /// One or more values to match against the specified key.
        public let values: [String]

        @inlinable
        public init(key: FilterName, matchOption: MatchOption, values: [String]) {
            self.key = key
            self.matchOption = matchOption
            self.values = values
        }

        public func validate(name: String) throws {
            try self.values.forEach {
                try validate($0, name: "values[]", parent: name, max: 1024)
                try validate($0, name: "values[]", parent: name, min: 1)
                try validate($0, name: "values[]", parent: name, pattern: "[\\S\\s]*")
            }
            try self.validate(self.values, name: "values", parent: name, min: 1)
        }

        private enum CodingKeys: String, CodingKey {
            case key = "key"
            case matchOption = "matchOption"
            case values = "values"
        }
    }

    public struct ListRecommendedActionsRequest: AWSEncodableShape {
        /// The criteria that you want all returned recommended actions to match.
        public let filter: RequestFilter?
        /// The maximum number of results to return in the response.
        public let maxResults: Int?
        /// The pagination token that indicates the next set of results that you want to retrieve.
        public let nextToken: String?

        @inlinable
        public init(filter: RequestFilter? = nil, maxResults: Int? = nil, nextToken: String? = nil) {
            self.filter = filter
            self.maxResults = maxResults
            self.nextToken = nextToken
        }

        public func validate(name: String) throws {
            try self.filter?.validate(name: "\(name).filter")
            try self.validate(self.maxResults, name: "maxResults", parent: name, max: 1000)
            try self.validate(self.maxResults, name: "maxResults", parent: name, min: 1)
            try self.validate(self.nextToken, name: "nextToken", parent: name, max: 8192)
            try self.validate(self.nextToken, name: "nextToken", parent: name, min: 1)
            try self.validate(self.nextToken, name: "nextToken", parent: name, pattern: "^[\\S\\s]*$")
        }

        private enum CodingKeys: String, CodingKey {
            case filter = "filter"
            case maxResults = "maxResults"
            case nextToken = "nextToken"
        }
    }

    public struct ListRecommendedActionsResponse: AWSDecodableShape {
        /// The pagination token that indicates the next set of results that you want to retrieve.
        public let nextToken: String?
        /// The list of recommended actions that satisfy the filter criteria.
        public let recommendedActions: [RecommendedAction]

        @inlinable
        public init(nextToken: String? = nil, recommendedActions: [RecommendedAction]) {
            self.nextToken = nextToken
            self.recommendedActions = recommendedActions
        }

        private enum CodingKeys: String, CodingKey {
            case nextToken = "nextToken"
            case recommendedActions = "recommendedActions"
        }
    }

    public struct RecommendedAction: AWSDecodableShape {
        /// The account that the recommended action is for.
        public let accountId: String?
        /// Context that applies to the recommended action.
        public let context: [String: String]?
        /// The feature associated with the recommended action.
        public let feature: Feature?
        /// The ID for the recommended action.
        public let id: String?
        /// The time when the recommended action status was last updated.
        public let lastUpdatedTimeStamp: String?
        /// The possible next steps to execute the recommended action.
        public let nextSteps: [String]?
        /// The severity associated with the recommended action.
        public let severity: Severity?
        /// The type of action you can take by adopting the recommended action.
        public let type: ActionType?

        @inlinable
        public init(accountId: String? = nil, context: [String: String]? = nil, feature: Feature? = nil, id: String? = nil, lastUpdatedTimeStamp: String? = nil, nextSteps: [String]? = nil, severity: Severity? = nil, type: ActionType? = nil) {
            self.accountId = accountId
            self.context = context
            self.feature = feature
            self.id = id
            self.lastUpdatedTimeStamp = lastUpdatedTimeStamp
            self.nextSteps = nextSteps
            self.severity = severity
            self.type = type
        }

        private enum CodingKeys: String, CodingKey {
            case accountId = "accountId"
            case context = "context"
            case feature = "feature"
            case id = "id"
            case lastUpdatedTimeStamp = "lastUpdatedTimeStamp"
            case nextSteps = "nextSteps"
            case severity = "severity"
            case type = "type"
        }
    }

    public struct RequestFilter: AWSEncodableShape {
        /// A list of action filters that define criteria for filtering results. Each filter specifies a key, match option, and corresponding values to filter on.
        public let actions: [ActionFilter]?

        @inlinable
        public init(actions: [ActionFilter]? = nil) {
            self.actions = actions
        }

        public func validate(name: String) throws {
            try self.actions?.forEach {
                try $0.validate(name: "\(name).actions[]")
            }
        }

        private enum CodingKeys: String, CodingKey {
            case actions = "actions"
        }
    }

    public struct ValidationException: AWSErrorShape {
        /// Lists each problematic field and why it failed validation.
        public let fieldList: [ValidationExceptionField]?
        public let message: String
        /// Provides a single, overarching explanation for the validation failure.
        public let reason: ValidationExceptionReason

        @inlinable
        public init(fieldList: [ValidationExceptionField]? = nil, message: String, reason: ValidationExceptionReason) {
            self.fieldList = fieldList
            self.message = message
            self.reason = reason
        }

        private enum CodingKeys: String, CodingKey {
            case fieldList = "fieldList"
            case message = "message"
            case reason = "reason"
        }
    }

    public struct ValidationExceptionField: AWSDecodableShape {
        /// Provides a message explaining why the field failed validation.
        public let message: String
        /// Provides the name of the field that failed validation.
        public let name: String

        @inlinable
        public init(message: String, name: String) {
            self.message = message
            self.name = name
        }

        private enum CodingKeys: String, CodingKey {
            case message = "message"
            case name = "name"
        }
    }
}

// MARK: - Errors

/// Error enum for BCMRecommendedActions
public struct BCMRecommendedActionsErrorType: AWSErrorType {
    enum Code: String {
        case accessDeniedException = "AccessDeniedException"
        case internalServerException = "InternalServerException"
        case throttlingException = "ThrottlingException"
        case validationException = "ValidationException"
    }

    private let error: Code
    public let context: AWSErrorContext?

    /// initialize BCMRecommendedActions
    public init?(errorCode: String, context: AWSErrorContext) {
        guard let error = Code(rawValue: errorCode) else { return nil }
        self.error = error
        self.context = context
    }

    internal init(_ error: Code) {
        self.error = error
        self.context = nil
    }

    /// return error code string
    public var errorCode: String { self.error.rawValue }

    /// You do not have sufficient access to perform this action.
    public static var accessDeniedException: Self { .init(.accessDeniedException) }
    /// An unexpected error occurred during the processing of your request.
    public static var internalServerException: Self { .init(.internalServerException) }
    /// The request was denied due to request throttling.
    public static var throttlingException: Self { .init(.throttlingException) }
    /// The input fails to satisfy the constraints specified by an Amazon Web Services service.
    public static var validationException: Self { .init(.validationException) }
}

extension BCMRecommendedActionsErrorType: AWSServiceErrorType {
    public static let errorCodeMap: [String: AWSErrorShape.Type] = [
        "ValidationException": BCMRecommendedActions.ValidationException.self
    ]
}

extension BCMRecommendedActionsErrorType: Equatable {
    public static func == (lhs: BCMRecommendedActionsErrorType, rhs: BCMRecommendedActionsErrorType) -> Bool {
        lhs.error == rhs.error
    }
}

extension BCMRecommendedActionsErrorType: CustomStringConvertible {
    public var description: String {
        return "\(self.error.rawValue): \(self.message ?? "")"
    }
}
